/*     */ package com.zimbra.cs.service;
/*     */ 
/*     */ import com.google.common.collect.Lists;
/*     */ import com.zimbra.client.ZFolder.Color;
/*     */ import com.zimbra.client.ZFolder.View;
/*     */ import com.zimbra.client.ZMailbox;
/*     */ import com.zimbra.client.ZMailbox.Options;
/*     */ import com.zimbra.client.ZMailbox.OwnerBy;
/*     */ import com.zimbra.client.ZMailbox.SharedItemBy;
/*     */ import com.zimbra.client.ZMountpoint;
/*     */ import com.zimbra.common.account.ZAttrProvisioning.MailStatus;
/*     */ import com.zimbra.common.localconfig.DebugConfig;
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.util.BlobMetaData;
/*     */ import com.zimbra.common.util.L10nUtil;
/*     */ import com.zimbra.common.util.L10nUtil.MsgKey;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Account;
/*     */ import com.zimbra.cs.account.AuthToken;
/*     */ import com.zimbra.cs.account.AuthTokenException;
/*     */ import com.zimbra.cs.account.Domain;
/*     */ import com.zimbra.cs.account.ExtAuthTokenKey;
/*     */ import com.zimbra.cs.account.GuestAccount;
/*     */ import com.zimbra.cs.account.NamedEntry;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Provisioning.GroupMembership;
/*     */ import com.zimbra.cs.account.SearchAccountsOptions;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.account.ShareInfoData;
/*     */ import com.zimbra.cs.account.ZimbraAuthToken;
/*     */ import com.zimbra.cs.ldap.ZLdapFilterFactory;
/*     */ import com.zimbra.cs.mailbox.Flag.FlagInfo;
/*     */ import com.zimbra.cs.mailbox.MailItem.Type;
/*     */ import com.zimbra.cs.mailbox.Mailbox;
/*     */ import com.zimbra.cs.mailbox.MailboxManager;
/*     */ import com.zimbra.cs.mailbox.Mountpoint;
/*     */ import com.zimbra.cs.mailbox.acl.AclPushSerializer;
/*     */ import com.zimbra.cs.servlet.ZimbraServlet;
/*     */ import com.zimbra.cs.util.AccountUtil;
/*     */ import com.zimbra.cs.util.WebClientServiceUtil;
/*     */ import com.zimbra.soap.mail.message.FolderActionRequest;
/*     */ import com.zimbra.soap.mail.type.FolderActionSelector;
/*     */ import java.io.IOException;
/*     */ import java.io.PrintWriter;
/*     */ import java.util.HashMap;
/*     */ import java.util.HashSet;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ import javax.servlet.RequestDispatcher;
/*     */ import javax.servlet.ServletContext;
/*     */ import javax.servlet.ServletException;
/*     */ import javax.servlet.http.Cookie;
/*     */ import javax.servlet.http.HttpServletRequest;
/*     */ import javax.servlet.http.HttpServletResponse;
/*     */ import org.apache.commons.codec.binary.Hex;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class ExternalUserProvServlet
/*     */   extends ZimbraServlet
/*     */ {
/*  76 */   private static final Log logger = LogFactory.getLog(ExternalUserProvServlet.class);
/*     */   private static final String EXT_USER_PROV_ON_UI_NODE = "/fromservice/extuserprov";
/*     */   private static final String PUBLIC_LOGIN_ON_UI_NODE = "/fromservice/publiclogin";
/*     */   public static final String PUBLIC_EXTUSERPROV_JSP = "/public/extuserprov.jsp";
/*     */   public static final String PUBLIC_LOGIN_JSP = "/public/login.jsp";
/*     */   
/*     */   public void init() throws ServletException
/*     */   {
/*  84 */     String name = getServletName();
/*  85 */     ZimbraLog.account.info("Servlet " + name + " starting up");
/*  86 */     super.init();
/*     */   }
/*     */   
/*     */   public void destroy()
/*     */   {
/*  91 */     String name = getServletName();
/*  92 */     ZimbraLog.account.info("Servlet " + name + " shutting down");
/*  93 */     super.destroy();
/*     */   }
/*     */   
/*     */   protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
/*     */   {
/*  98 */     String param = req.getParameter("p");
/*  99 */     if (param == null) {
/* 100 */       throw new ServletException("request missing param");
/*     */     }
/* 102 */     Map<Object, Object> tokenMap = validatePrelimToken(param);
/* 103 */     Map<String, String> reqHeaders = new HashMap();
/* 104 */     String ownerId = (String)tokenMap.get("aid");
/* 105 */     String folderId = (String)tokenMap.get("fid");
/* 106 */     String extUserEmail = (String)tokenMap.get("email");
/*     */     
/* 108 */     Provisioning prov = Provisioning.getInstance();
/*     */     try
/*     */     {
/* 111 */       Account owner = prov.getAccountById(ownerId);
/* 112 */       Domain domain = prov.getDomain(owner);
/* 113 */       Account grantee = prov.getAccountByName(mapExtEmailToAcctName(extUserEmail, domain));
/* 114 */       if (grantee == null)
/*     */       {
/* 116 */         if ((prov.isOctopus()) && (DebugConfig.skipVirtualAccountRegistrationPage))
/*     */         {
/*     */ 
/* 119 */           provisionVirtualAccountAndRedirect(req, resp, null, null, ownerId, extUserEmail);
/*     */         } else {
/* 121 */           resp.addCookie(new Cookie("ZM_PRELIM_AUTH_TOKEN", param));
/* 122 */           req.setAttribute("extuseremail", extUserEmail);
/* 123 */           if (WebClientServiceUtil.isServerInSplitMode()) {
/* 124 */             reqHeaders.put("extuseremail", extUserEmail);
/* 125 */             reqHeaders.put("ZM_PRELIM_AUTH_TOKEN", param);
/* 126 */             String htmlresp = WebClientServiceUtil.sendServiceRequestToOneRandomUiNode("/fromservice/extuserprov", reqHeaders);
/* 127 */             resp.getWriter().print(htmlresp);
/*     */           } else {
/* 129 */             ServletContext context = getServletContext().getContext("/zimbra");
/* 130 */             if (context != null) {
/* 131 */               RequestDispatcher dispatcher = context.getRequestDispatcher("/public/extuserprov.jsp");
/*     */               
/* 133 */               dispatcher.forward(req, resp);
/*     */             } else {
/* 135 */               logger.warn("Could not access servlet context url /zimbra");
/* 136 */               throw ServiceException.TEMPORARILY_UNAVAILABLE();
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/*     */       else
/*     */       {
/* 143 */         String[] sharedItems = owner.getSharedItem();
/* 144 */         int sharedFolderId = Integer.valueOf(folderId).intValue();
/* 145 */         String sharedFolderPath = null;
/* 146 */         MailItem.Type sharedFolderView = null;
/* 147 */         for (String sharedItem : sharedItems) {
/* 148 */           ShareInfoData sid = AclPushSerializer.deserialize(sharedItem);
/* 149 */           if ((sid.getItemId() == sharedFolderId) && (extUserEmail.equalsIgnoreCase(sid.getGranteeId()))) {
/* 150 */             sharedFolderPath = sid.getPath();
/* 151 */             sharedFolderView = sid.getFolderDefaultViewCode();
/* 152 */             break;
/*     */           }
/*     */         }
/* 155 */         if (sharedFolderPath == null) {
/* 156 */           throw new ServletException("share not found");
/*     */         }
/* 158 */         String mountpointName = getMountpointName(owner, grantee, sharedFolderPath);
/*     */         
/* 160 */         ZMailbox.Options options = new ZMailbox.Options();
/* 161 */         options.setNoSession(true);
/* 162 */         options.setAuthToken(AuthProvider.getAuthToken(grantee).toZAuthToken());
/* 163 */         options.setUri(AccountUtil.getSoapUri(grantee));
/* 164 */         ZMailbox zMailbox = new ZMailbox(options);
/* 165 */         ZMountpoint zMtpt = null;
/*     */         try {
/* 167 */           zMtpt = zMailbox.createMountpoint(String.valueOf(getMptParentFolderId(sharedFolderView, prov)), mountpointName, ZFolder.View.fromString(sharedFolderView.toString()), ZFolder.Color.DEFAULTCOLOR, null, ZMailbox.OwnerBy.BY_ID, ownerId, ZMailbox.SharedItemBy.BY_ID, folderId, false);
/*     */ 
/*     */         }
/*     */         catch (ServiceException e)
/*     */         {
/* 172 */           logger.debug("Error in attempting to create mountpoint. Probably it already exists.", e);
/*     */         }
/* 174 */         if (zMtpt != null) {
/* 175 */           if (sharedFolderView == MailItem.Type.APPOINTMENT)
/*     */           {
/* 177 */             FolderActionSelector actionSelector = new FolderActionSelector(zMtpt.getId(), "check");
/* 178 */             FolderActionRequest actionRequest = new FolderActionRequest(actionSelector);
/*     */             try {
/* 180 */               zMailbox.invokeJaxb(actionRequest);
/*     */             } catch (ServiceException e) {
/* 182 */               logger.warn("Error in invoking check action on calendar mountpoint", e);
/*     */             }
/*     */           }
/* 185 */           HashSet<MailItem.Type> types = new HashSet();
/* 186 */           types.add(sharedFolderView);
/* 187 */           enableAppFeatures(grantee, types);
/*     */         }
/*     */         
/*     */ 
/* 191 */         String zAuthTokenCookie = null;
/* 192 */         Cookie[] cookies = req.getCookies();
/* 193 */         if (cookies != null) {
/* 194 */           for (Cookie cookie : cookies) {
/* 195 */             if (cookie.getName().equals("ZM_AUTH_TOKEN")) {
/* 196 */               zAuthTokenCookie = cookie.getValue();
/* 197 */               break;
/*     */             }
/*     */           }
/*     */         }
/* 201 */         AuthToken zAuthToken = null;
/* 202 */         if (zAuthTokenCookie != null) {
/*     */           try {
/* 204 */             zAuthToken = AuthProvider.getAuthToken(zAuthTokenCookie);
/*     */           }
/*     */           catch (AuthTokenException ignored) {}
/*     */         }
/*     */         
/* 209 */         if ((zAuthToken != null) && (!zAuthToken.isExpired()) && (zAuthToken.isRegistered()) && (grantee.getId().equals(zAuthToken.getAccountId())))
/*     */         {
/* 211 */           resp.sendRedirect("/");
/* 212 */         } else if ((prov.isOctopus()) && (!grantee.isVirtualAccountInitialPasswordSet()) && (DebugConfig.skipVirtualAccountRegistrationPage))
/*     */         {
/*     */ 
/*     */ 
/* 216 */           setCookieAndRedirect(req, resp, grantee);
/*     */         } else {
/* 218 */           req.setAttribute("virtualacctdomain", domain.getName());
/* 219 */           if (WebClientServiceUtil.isServerInSplitMode()) {
/* 220 */             reqHeaders.put("virtualacctdomain", domain.getName());
/* 221 */             String htmlresp = WebClientServiceUtil.sendServiceRequestToOneRandomUiNode("/fromservice/publiclogin", reqHeaders);
/* 222 */             resp.getWriter().print(htmlresp);
/*     */           } else {
/* 224 */             RequestDispatcher dispatcher = getServletContext().getContext("/zimbra").getRequestDispatcher("/public/login.jsp");
/*     */             
/* 226 */             dispatcher.forward(req, resp);
/*     */           }
/*     */         }
/*     */       }
/*     */     } catch (ServiceException e) {
/* 231 */       throw new ServletException(e);
/*     */     }
/*     */   }
/*     */   
/*     */   private static String getMountpointName(Account owner, Account grantee, String sharedFolderPath) throws ServiceException
/*     */   {
/* 237 */     if (sharedFolderPath.startsWith("/")) {
/* 238 */       sharedFolderPath = sharedFolderPath.substring(1);
/*     */     }
/* 240 */     int index = sharedFolderPath.indexOf('/');
/* 241 */     if (index != -1)
/*     */     {
/* 243 */       sharedFolderPath = sharedFolderPath.substring(index + 1);
/*     */     }
/* 245 */     return L10nUtil.getMessage(L10nUtil.MsgKey.shareNameDefault, grantee.getLocale(), new Object[] { getDisplayName(owner), sharedFolderPath.replace("/", " ") });
/*     */   }
/*     */   
/*     */   private static String getDisplayName(Account owner)
/*     */   {
/* 250 */     return owner.getDisplayName() != null ? owner.getDisplayName() : owner.getName();
/*     */   }
/*     */   
/*     */   private static String mapExtEmailToAcctName(String extUserEmail, Domain domain) {
/* 254 */     return extUserEmail.replace("@", ".") + "@" + domain.getName();
/*     */   }
/*     */   
/*     */   protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
/*     */   {
/* 259 */     String displayName = req.getParameter("displayname");
/* 260 */     String password = req.getParameter("password");
/*     */     
/* 262 */     String prelimToken = null;
/* 263 */     Cookie[] cookies = req.getCookies();
/* 264 */     if (cookies != null) {
/* 265 */       for (Cookie cookie : cookies) {
/* 266 */         if (cookie.getName().equals("ZM_PRELIM_AUTH_TOKEN")) {
/* 267 */           prelimToken = cookie.getValue();
/* 268 */           break;
/*     */         }
/*     */       }
/*     */     }
/* 272 */     if (prelimToken == null) {
/* 273 */       throw new ServletException("unauthorized request");
/*     */     }
/* 275 */     Map<Object, Object> tokenMap = validatePrelimToken(prelimToken);
/* 276 */     String ownerId = (String)tokenMap.get("aid");
/*     */     
/* 278 */     String extUserEmail = (String)tokenMap.get("email");
/*     */     
/* 280 */     provisionVirtualAccountAndRedirect(req, resp, displayName, password, ownerId, extUserEmail);
/*     */   }
/*     */   
/*     */   private static void provisionVirtualAccountAndRedirect(HttpServletRequest req, HttpServletResponse resp, String displayName, String password, String grantorId, String extUserEmail)
/*     */     throws ServletException
/*     */   {
/* 286 */     Provisioning prov = Provisioning.getInstance();
/*     */     try {
/* 288 */       Account owner = prov.getAccountById(grantorId);
/* 289 */       Domain domain = prov.getDomain(owner);
/* 290 */       Account grantee = prov.getAccountByName(mapExtEmailToAcctName(extUserEmail, domain));
/* 291 */       if (grantee != null) {
/* 292 */         throw new ServletException("invalid request: account already exists");
/*     */       }
/*     */       
/*     */ 
/* 296 */       SearchAccountsOptions searchOpts = new SearchAccountsOptions(domain, new String[] { "zimbraId", "displayName", "zimbraSharedItem" });
/*     */       
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/* 302 */       GuestAccount guestAcct = new GuestAccount(extUserEmail, null);
/* 303 */       List<String> groupIds = prov.getGroupMembership(guestAcct, false).groupIds();
/* 304 */       List<String> grantees = Lists.newArrayList(new String[] { extUserEmail });
/* 305 */       grantees.addAll(groupIds);
/* 306 */       searchOpts.setFilter(ZLdapFilterFactory.getInstance().accountsByGrants(grantees, false, false));
/* 307 */       List<NamedEntry> accounts = prov.searchDirectory(searchOpts);
/*     */       
/* 309 */       if (accounts.isEmpty()) {
/* 310 */         throw new ServletException("no shares discovered");
/*     */       }
/*     */       
/*     */ 
/* 314 */       Map<String, Object> attrs = new HashMap();
/* 315 */       attrs.put("zimbraIsExternalVirtualAccount", "TRUE");
/* 316 */       attrs.put("zimbraExternalUserMailAddress", extUserEmail);
/* 317 */       attrs.put("zimbraMailHost", prov.getLocalServer().getServiceHostname());
/* 318 */       if (!StringUtil.isNullOrEmpty(displayName)) {
/* 319 */         attrs.put("displayName", displayName);
/*     */       }
/* 321 */       attrs.put("zimbraHideInGal", "TRUE");
/* 322 */       attrs.put("zimbraMailStatus", ZAttrProvisioning.MailStatus.disabled.toString());
/* 323 */       if (!StringUtil.isNullOrEmpty(password)) {
/* 324 */         attrs.put("zimbraVirtualAccountInitialPasswordSet", "TRUE");
/*     */       }
/* 326 */       grantee = prov.createAccount(mapExtEmailToAcctName(extUserEmail, domain), password, attrs);
/*     */       
/*     */       Mailbox granteeMbox;
/*     */       try
/*     */       {
/* 331 */         granteeMbox = MailboxManager.getInstance().getMailboxByAccount(grantee);
/*     */       }
/*     */       catch (ServiceException e)
/*     */       {
/* 335 */         prov.deleteAccount(grantee.getId());
/* 336 */         throw e;
/*     */       }
/*     */       
/*     */ 
/* 340 */       Set<MailItem.Type> viewTypes = new HashSet();
/* 341 */       for (NamedEntry ne : accounts) {
/* 342 */         Account account = (Account)ne;
/* 343 */         String[] sharedItems = account.getSharedItem();
/* 344 */         for (String sharedItem : sharedItems) {
/* 345 */           ShareInfoData shareData = AclPushSerializer.deserialize(sharedItem);
/* 346 */           if (granteeMatchesShare(shareData, grantee))
/*     */           {
/*     */ 
/* 349 */             String sharedFolderPath = shareData.getPath();
/* 350 */             String mountpointName = getMountpointName(account, grantee, sharedFolderPath);
/* 351 */             MailItem.Type viewType = shareData.getFolderDefaultViewCode();
/* 352 */             Mountpoint mtpt = granteeMbox.createMountpoint(null, getMptParentFolderId(viewType, prov), mountpointName, account.getId(), shareData.getItemId(), shareData.getItemUuid(), viewType, 0, (byte)0, false);
/*     */             
/*     */ 
/* 355 */             if (viewType == MailItem.Type.APPOINTMENT)
/*     */             {
/* 357 */               granteeMbox.alterTag(null, mtpt.getId(), mtpt.getType(), Flag.FlagInfo.CHECKED, true, null);
/*     */             }
/* 359 */             viewTypes.add(viewType);
/*     */           }
/*     */         } }
/* 362 */       enableAppFeatures(grantee, viewTypes);
/*     */       
/* 364 */       setCookieAndRedirect(req, resp, grantee);
/*     */     } catch (Exception e) {
/* 366 */       throw new ServletException(e);
/*     */     }
/*     */   }
/*     */   
/*     */   private static boolean granteeMatchesShare(ShareInfoData shareData, Account acct) throws ServiceException {
/* 371 */     Provisioning prov = Provisioning.getInstance();
/* 372 */     String grantee = shareData.getGranteeId();
/* 373 */     byte granteeType = shareData.getGranteeTypeCode();
/* 374 */     switch (granteeType) {
/* 375 */     case 2:  return prov.inACLGroup(acct, grantee);
/* 376 */     case 7:  return grantee.equalsIgnoreCase(acct.getExternalUserMailAddress()); }
/* 377 */     return false;
/*     */   }
/*     */   
/*     */   private static void setCookieAndRedirect(HttpServletRequest req, HttpServletResponse resp, Account grantee)
/*     */     throws ServiceException, IOException
/*     */   {
/* 383 */     AuthToken authToken = AuthProvider.getAuthToken(grantee);
/* 384 */     authToken.encode(resp, false, req.getScheme().equals("https"));
/* 385 */     resp.sendRedirect("/");
/*     */   }
/*     */   
/*     */   private static int getMptParentFolderId(MailItem.Type viewType, Provisioning prov) throws ServiceException {
/* 389 */     switch (viewType) {
/*     */     case DOCUMENT: 
/* 391 */       if (prov.isOctopus())
/* 392 */         return 16;
/*     */       break;
/*     */     }
/* 395 */     return 1;
/*     */   }
/*     */   
/*     */   private static void enableAppFeatures(Account grantee, Set<MailItem.Type> viewTypes) throws ServiceException
/*     */   {
/* 400 */     Map<String, Object> appFeatureAttrs = new HashMap();
/* 401 */     for (MailItem.Type type : viewTypes) {
/* 402 */       switch (type) {
/*     */       case DOCUMENT: 
/* 404 */         appFeatureAttrs.put("zimbraFeatureBriefcasesEnabled", "TRUE");
/* 405 */         break;
/*     */       case APPOINTMENT: 
/* 407 */         appFeatureAttrs.put("zimbraFeatureCalendarEnabled", "TRUE");
/* 408 */         break;
/*     */       case CONTACT: 
/* 410 */         appFeatureAttrs.put("zimbraFeatureContactsEnabled", "TRUE");
/* 411 */         break;
/*     */       case TASK: 
/* 413 */         appFeatureAttrs.put("zimbraFeatureTasksEnabled", "TRUE");
/* 414 */         break;
/*     */       case MESSAGE: 
/* 416 */         appFeatureAttrs.put("zimbraFeatureMailEnabled", "TRUE");
/*     */       }
/*     */       
/*     */     }
/*     */     
/*     */ 
/* 422 */     grantee.modify(appFeatureAttrs);
/*     */   }
/*     */   
/*     */   public static Map<Object, Object> validatePrelimToken(String param) throws ServletException {
/* 426 */     int pos = param.indexOf('_');
/* 427 */     if (pos == -1) {
/* 428 */       throw new ServletException("invalid token param");
/*     */     }
/* 430 */     String ver = param.substring(0, pos);
/* 431 */     int pos2 = param.indexOf('_', pos + 1);
/* 432 */     if (pos2 == -1) {
/* 433 */       throw new ServletException("invalid token param");
/*     */     }
/* 435 */     String hmac = param.substring(pos + 1, pos2);
/* 436 */     String data = param.substring(pos2 + 1);
/*     */     Map<Object, Object> map;
/*     */     try {
/* 439 */       ExtAuthTokenKey key = ExtAuthTokenKey.getVersion(ver);
/* 440 */       if (key == null) {
/* 441 */         throw new ServletException("unknown key version");
/*     */       }
/* 443 */       String computedHmac = ZimbraAuthToken.getHmac(data, key.getKey());
/* 444 */       if (!computedHmac.equals(hmac)) {
/* 445 */         throw new ServletException("hmac failure");
/*     */       }
/* 447 */       String decoded = new String(Hex.decodeHex(data.toCharArray()));
/* 448 */       map = BlobMetaData.decode(decoded);
/*     */     } catch (Exception e) {
/* 450 */       throw new ServletException(e);
/*     */     }
/* 452 */     Object expiry = map.get("exp");
/* 453 */     if (expiry != null)
/*     */     {
/* 455 */       if (System.currentTimeMillis() > Long.parseLong((String)expiry)) {
/* 456 */         throw new ServletException("url no longer valid");
/*     */       }
/*     */     }
/* 459 */     return map;
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/service/ExternalUserProvServlet.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */